<template>
  <div class="container">

    <div class="mb-3 row">
      <div class="col-md-10">
        <span>Here you can interactively play and test components with a fresh vue instance.</span>
        <br>
        <Strong>TIP: </Strong>
        <span>You can clone docs repo, to hack and develop components.</span>
        <span> changes will be reflected and hot-reloaded instantly.</span>
        <br>
        <span>Please refer to</span>
        <router-link to="/docs"> Docs </router-link>
        <span>for more info about available tags and usage.</span>
      </div>
      <div class="col-md-1">
        <form
          method="post"
          action="https://jsfiddle.net/api/post/library/pure/"
          target="_blank"
          v-if="vm">
          <input
            type="hidden"
            :value="html_fiddle"
            name="html">
          <input
            type="hidden"
            :value="js_fiddle"
            name="js">
          <input
            type="hidden"
            value="l"
            name="js_wrap">
          <input
            name="resources"
            type="hidden"
            :value="fiddle_dependencies.join(',')">
          <b-btn
            size="sm"
            type="submit">
            <span>Export to JSFiddle</span>
          </b-btn>
        </form>
      </div>
    </div>

    <transition-group
      class="row"
      tag="div"
      name="flip">
      <div
        key="A"
        :class="full?'col-12':'col'">
        <transition-group
          class="row"
          tag="div"
          name="flip">
          <div
            :class="`col-md-${(vertical&&!full)?6:12} col-sm-12`"
            key="A1">
            <!--Template-->
            <div class="card mt-2">
              <div class="card-header card-outline-info">
                <span>Template</span>
                <b-btn
                  size="sm"
                  @click="toggleFull"
                  variant="outline-info"
                  class="float-right">
                  <span>{{ full ? 'Split' : 'Full' }}</span>
                </b-btn>
              </div>
              <codemirror
                v-model="html"
                mode="htmlmixed"/>
            </div>
          </div>
          <div
            :class="`col-md-${(vertical&&!full)?6:12} col-sm-12`"
            key="A2">
            <!--JS-->
            <div class="card mt-2">
              <div class="card-header card-outline-warning">
                <span>JS</span>
                <b-btn
                  size="sm"
                  @click="toggleFull"
                  variant="outline-info"
                  class="float-right">
                  <span>{{ full ? 'Split' : 'Full' }}</span>
                </b-btn>
              </div>
              <codemirror
                v-model="js"
                mode="javascript"/>
            </div>
          </div>
        </transition-group>
      </div>

      <div
        key="B"
        :class="`col-md-${(vertical || full)?12:6} col-sm-12`">
        <!--Result-->
        <div class="card mt-2">
          <div class="card-header card-outline-success">
            <span>Result</span>
            <b-btn
              size="sm"
              @click="toggleVertical"
              variant="outline-info"
              class="float-right"
              v-if="!full">
              <span>{{ vertical ? 'Horizontal' : 'Vertical' }}</span>
            </b-btn>
          </div>
          <div class="card-body">
            <div
              id="result-container"
              ref="result"/>
          </div>
        </div>

        <!--Console-->
        <div class="">
          <div class="card mt-2">
            <div class="card-header card-outline-secondary">
              <span>Console</span>
              <b-btn
                size="sm"
                @click="clear"
                variant="outline-danger"
                class="float-right"
                v-if="messages.length">
                <span>Clear</span>
              </b-btn>
            </div>
            <div class="card-body">
              <div
                v-for="(message, idx) in messages"
                :key="`console-${idx}`">
                <b-badge :variant="message[0]">{{ message[0] }}</b-badge>
                <span class="text-muted"> {{ message[1] }}</span>
                <br>
              </div>
            </div>
          </div>
        </div>
      </div>
    </transition-group>

  </div>
</template>

<style>
.flip-move {
    transition: all .3s;
}
</style>

<script>
import Vue from 'vue'
import debounce from 'lodash/debounce'

const defaultJS = `{
    data: {
        name: 'Zeus'
    },
}`
const defaultHTML = `<b-alert show> Hello {{ name }}! </b-alert>`

export default {
  data () {
    return {
      html: '',
      js: '',
      vm: null,
      messages: [],
      originalLog: null,
      originalWarn: null,
      originalError: null,
      vertical: false,
      full: false,
      lazy_run_: null
    }
  },
  head () {
    return {
      title: 'Playground - BootstrapVue'
    }
  },
  computed: {
    fiddle_dependencies () {
      return [
        '//unpkg.com/bootstrap/dist/css/bootstrap.min.css',
        '//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.css',
        '//unpkg.com/vue@latest/dist/vue.min.js',
        '//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.js'
      ]
    },
    js_fiddle () {
      const js = `new Vue({el:'#app',\r\n${this.js.trim()}})`.trim()
      return `window.onload = function() {${js}}`
    },
    html_fiddle () {
      return `<div id='app'>\r\n${this.html}\r\n</div>`.trim()
    },
    lazy_run () {
      if (!this.lazy_run_) {
        this.lazy_run_ = debounce(this.run.bind(this), 500)
      }
      return this.lazy_run_
    }
  },
  watch: {
    html () {
      this.lazy_run()
    },
    js () {
      this.lazy_run()
    }
  },
  mounted () {
    this.load()
    this.run()

    if (typeof window !== 'undefined') {
      this.originalLog = console.log
      this.originalWarn = console.warn
      this.originalError = console.error
      const self = this

      console.warn = function () {
        self.log('warning', arguments)
      }

      console.log = function () {
        self.log('info', arguments)
      }

      console.error = function () {
        self.log('danger', arguments)
      }
    }
  },
  beforeDestroy () {
    if (typeof window !== 'undefined') {
      console.log = this.originalLog
      console.warn = this.originalWarn
      console.error = this.originalError
    }
    this.destroyVM()
  },
  methods: {
    log (tag, args) {
      // We have to ignore props mutation warning due to vue bug when we have two instances
      if (String(args[0]).indexOf('Avoid mutating a prop directly') !== -1) {
        return
      }

      const argsArr = [tag]
      for (let i = 0; i < args.length; i++) {
        argsArr.push(args[i])
      }

      this.originalLog.apply(console, argsArr)

      if (this.messages.length > 10) {
        this.messages.splice(10)
      }
      this.messages.unshift([argsArr.shift(), argsArr.map(String).join(' ')])
    },
    destroyVM () {
      if (this.vm) {
        try {
          this.vm.$destroy()
        } catch (err) {
        }
        this.vm = null
      }
    },
    run () {
      // Commit latest changes
      this.commit()

      // Destroy old VM if exists
      this.destroyVM()

      // Set HTML
      this.$refs.result.innerHTML = `<div id="result"></div>`

      // Clear messages
      this.clear()

      // Try Create new VM
      try {
        let options
        try {
          /* eslint-disable no-eval */
          let js = this.js.trim()
          if (js.indexOf('{') !== 0) {
            js = `{${js}}`
          }
          eval(`options= ${js}`)
        } catch (err) {
          throw new Error(`Compiling JS: ${err}`)
        }
        options.router = this.$router
        options.el = '#result'
        options.template = `<div>${this.html}</div>`
        this.vm = new Vue(options)
      } catch (err) {
        console.error(err)
      }
    },
    toggleVertical () {
      this.vertical = !this.vertical
    },
    toggleFull () {
      this.full = !this.full
    },
    clear () {
      this.messages.splice(0)
    },
    load () {
      if (typeof window === 'undefined' || !window.localStorage) {
        return
      }
      this.js = window.localStorage.getItem('playground_js') || defaultJS.trim()
      this.html = window.localStorage.getItem('playground_html') || defaultHTML.trim()
    },
    commit () {
      if (typeof window === 'undefined' || !window.localStorage) {
        return
      }
      window.localStorage.setItem('playground_js', this.js)
      window.localStorage.setItem('playground_html', this.html)
    }
  }
}
</script>
